package com.tjetc.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tjetc.common.AlipayInfo;
import com.tjetc.common.JsonResult;
import com.tjetc.common.MerchantDeploymentInfo;
import com.tjetc.dao.*;
import com.tjetc.entity.*;
import com.tjetc.model.AdminMoneyInfo;
import com.tjetc.model.OrderMerchantUser;
import com.tjetc.service.AdminService;
import com.tjetc.service.MerchantService;
import com.tjetc.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.Local;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private SnowflakeIdWorkerService snowflakeIdWorkerService;
    @Autowired
    private UserAddressMapper userAddressMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    AlipayClient alipayClient;
    @Autowired
    DailyAmountMapper dailyAmountMapper;
    @Autowired
    MonthlyAmountMapper monthlyAmountMapper;
    @Autowired
    MerchantService merchantService;
    @Autowired
    AdminService adminService;
    @Autowired
    MerchantDeploymentInfo merchantDeploymentInfo;
    @Autowired
    private AlipayInfo alipayInfo;
    /***
     * 用户下单
     * @param order
     * @param list
     * @return
     */
    @Transactional
    @Override
    public int addToOrder(Order order, List<Integer> list) {
        //生成订单编号
        Long snowId = snowflakeIdWorkerService.generateUserId();
        String number = snowId.toString();
        //设置订单编号
        order.setNumber(number);
        //设置为待付款
        order.setStatus(0);
        //设置下单时间
        order.setOrderTime(LocalDateTime.now());
        //补全order信息
        Integer addId = order.getAddressBookId();
        UserAddress address = userAddressMapper.selectById(addId);
        order.setPhone(address.getPhone());
        order.setConsignee(address.getConsignee());
        order.setAddress(address.getProvinceName() + address.getCityName() + address.getDistrictName() + address.getDetail());
        System.out.println(order);
        int orderId;
        //插入订单
        orderMapper.add(order);
        orderId = order.getId();
        if (orderId == 0) {
            log.error("orderId为0");
            throw new RuntimeException("添加订单失败");
        }
        // 商品详细加入到表中
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.selectByIdList(list);
        List<Integer> dishId = new ArrayList<>();
        for (int i = 0; i < shoppingCarts.size(); i++) {
            dishId.add(shoppingCarts.get(i).getDishId());
        }
        List<Dish> dishes = dishMapper.selectByList(dishId);
        // 订单详情
        List<OrderDetail> orderDetails = new ArrayList<>();
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(orderId);
        //判断菜品库存是否充足，库存为菜品字段，需要逐个判断
        for (int i = 0; i < dishes.size(); i++) {
            orderDetail.setDishId(dishes.get(i).getId());
            orderDetail.setImage(dishes.get(i).getImage());
            int num = shoppingCarts.get(i).getNumber();
            //判断库存是否充足
            if (num > dishes.get(i).getInventory()) {
                log.error("菜品：" + dishes.get(i).getName() + "库存不足");
                throw new RuntimeException("菜品库存不足");
            } else {
                //更新库存
                dishMapper.deleteDishInventory(num, dishes.get(i).getId());
            }
            //将订单详细的信息添加到订单详情表中
            orderDetail.setNumber(num);
            BigDecimal price = dishes.get(i).getPrice();
            orderDetail.setPrice(price);
            orderDetail.setAmount(price.multiply(BigDecimal.valueOf(num)));
            orderDetails.add(orderDetail);
            orderDetailMapper.addOrderDetail(orderDetail);
        }
        //删除购物车
        int rows = shoppingCartMapper.deleteList(list);
        if (rows != list.size()) {
            throw new RuntimeException("购物车删除的行数与实际行数不符");
        }
        //返回订单id
        return orderId;
    }

    /***
     * 商家添加订单
     * @param order
     * @return
     */
    @Override
    public int add(Order order) {
        Long snowId = snowflakeIdWorkerService.generateUserId();
        order.setNumber(snowId.toString());
        return orderMapper.add(order);
    }

    /***
     * 订单id查询订单信息
     * @param id
     * @return
     */
    @Override
    public Order selectByOrderId(int id) {
        return orderMapper.selectByOrderId(id);
    }

    /***
     * 用户id查询订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectByUserId(int userId) {
        return orderMapper.selectByUserId(userId);
    }

    /***
     * 查询用户待支付订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectWaitPay(int userId) {
        return orderMapper.selectWaitPay(userId);
    }

    /***
     * 查询用户待送达订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectWaitArrive(int userId) {
        return orderMapper.selectWaitArrive(userId);
    }

    /***
     * 查询用户待评论订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectWaitRemark(int userId) {
        return orderMapper.selectWaitRemark(userId);
    }

    /***
     * 查询用户未完成订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectUnaccomplished(int userId) {
        return orderMapper.selectUnaccomplished(userId);
    }


    /***
     * 查询申请退款的订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectRefund(int userId) {
        return orderMapper.selectRefund(userId);
    }

    /***
     * 查询用户待退款或已退款订单
     * @param userId
     * @return
     */
    @Override
    public List<Order> selectAfterPay(int userId) {
        return orderMapper.selectAfterPay(userId);
    }

    /***
     * 商家id查询订单信息
     * @param merchantId
     * @return
     */
    @Override
    public List<Order> selectAllByMerchantId(int merchantId) {
        return orderMapper.selectAllByMerchantId(merchantId);
    }


    /***
     * 根据订单id删除订单信息
     * @param id
     * @return
     */
    @Override
    public int delete(int id) {
        int i = orderDetailMapper.deleteByOrderId(id);
        if (i <= 0) {
            throw new RuntimeException("订单详情删除失败");
        }
        return orderMapper.delete(id);
    }

    /***
     * 管理员端更新订单信息
     * @param order
     * @return
     */
    @Transactional
    @Override
    public Integer updateOrder(Order order) {
        Order orderBefore = orderMapper.selectByOrderId(order.getId());
        if(orderBefore.getStatus() != 0 && order.getStatus() == 0) {
            throw new RuntimeException("已支付订单无法修改为未支付");
        }
        if(orderBefore.getStatus() == 3 || orderBefore.getStatus() == 4) {
            if(order.getStatus() <= 2) {
                throw new RuntimeException("已完成订单无法修改为未完成");
            }
        }
        if((order.getStatus() == 3 || order.getStatus() == 4) &&
                ((orderBefore.getStatus() != 3 && orderBefore.getStatus() != 4) || orderBefore.getCheckoutTime() == null)) {
            order.setCheckoutTime(LocalDateTime.now());
        }
        return orderMapper.update(order);
    }

    /**
     * 分页查询所有的订单
     * @param order 指定Order的条件对象，其中字段为null或者空字符串的话就不作为查询依据
     * @param pageNum 页面页数
     * @param pageSize 每页的元素数量
     * @return 返回前端处理对象，其中有页面分装对象
     */
    @Override
    public JsonResult<PageInfo> page(Order order, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<OrderMerchantUser> resultList = orderMapper.selectAllByOrder(order);
        return new JsonResult<>(0, "", new PageInfo(resultList));
    }

    /**
     * 创建支付订单，调用接口
     * @param orderId 指定订单id
     * @return 返回前端处理对象。如果调用支付宝接口调用成功，则将响应页面返回给前端，前端需要用body数据将页面跳转到第三方页面进行支付
     */
    @Transactional
    @Override
    public JsonResult alipay(Integer orderId) {
        // 根据订单id查询订单
        Order order = orderMapper.selectByOrderId(orderId);

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //异步接收地址，仅支持http/https，公网可访问
        /******必传参数******/
        JSONObject bizContent = new JSONObject();
        //商户订单号，商家自定义，保持唯一性
        bizContent.put("out_trade_no", order.getNumber());
        //支付金额，最小值0.01元
        bizContent.put("total_amount", order.getAmount());
        //订单标题，不可使用特殊符号
        bizContent.put("subject", "商品购买");
        //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        //同步跳转地址，仅支持http/https
        request.setNotifyUrl(alipayInfo.getNotifyUrl());
        request.setReturnUrl(alipayInfo.getReturnUrl());
        request.setBizContent(bizContent.toString());
        AlipayTradePagePayResponse response = null;
        try {
            // 执行请求，调用支付宝接口
            response = alipayClient.pageExecute(request);
        } catch (AlipayApiException e) {
            log.info("出现了异常");
            throw new RuntimeException(e);
        }
        if (response.isSuccess()) {
            log.info("调用成功");
            return new JsonResult(0, "", response.getBody());
        } else {
            log.info("调用失败");
            return new JsonResult(1, "创建支付交易失败", null);
        }
    }

    /**
     * 获取指定日期和指定商家的所有订单
     * @param day 指定日期
     * @param merchantId 指定商家id
     * @return 返回订单的列表
     */
    @Override
    public List<Order> getOrderByDayTime(LocalDateTime day, Integer merchantId) {
        return orderMapper.getOrderByDayTime(day, merchantId);
    }

    /**
     * 获取指定时间内所有的订单
     * @param start 开始时间
     * @param end 结束时间
     * @return 返回订单列表
     */
    @Override
    public List<Order> getOrderByStartTimeAndEndTime(LocalDateTime start, LocalDateTime end) {
        return orderMapper.getOrderByStartTimeAndEndTime(start, end);
    }

    /**
     * 查询指定月份下所有订单
     * @param month 传入时间。月份对即可
     * @return 返回所有订单列表
     */
    @Override
    public List<Order> getOrderByMonthTime(LocalDateTime month) {
        return orderMapper.getOrderByMonthTime(month);
    }

    /**
     * 根据商家id和时间，查询所有符合条件的订单
     * @param merchantId 商家id
     * @param time 时间
     * @return 返回所有订单列表
     */
    @Override
    public List<Order> selectByOrderAndDay(Integer merchantId, LocalDateTime time) {
        return orderMapper.getOrderByDayTime(time, merchantId);
    }

    /**
     * 管理端可以手动刷新指定月份的收入情况
     * @param time 传入指定时间
     * @param id 传入指定商家id
     */
    @Transactional
    @Override
    public void refresh(LocalDateTime time, Integer id) {
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(time.plusMonths(1).withDayOfMonth(1))) {
            throw new RuntimeException("该月份未到月底，无法结账");
        }
        // 假如当前时间已经被更新,则重新更新
        Boolean has_take = monthlyAmountMapper.selectByTimeAndId(id, time).size() >= 1;
        if (has_take) {
            // 获取最靠前的基准管理员
            Admin admin = adminService.listAll().get(0);
            // 获取当前商家
            Merchant merchant = merchantService.selectById(id);
            List<MonthlyAmount> monthlyAmounts = monthlyAmountMapper.selectByTimeAndId(id, time);
            MonthlyAmount monthlyAmount = monthlyAmounts.get(0);
            // 先退回
            admin.setAmount(admin.getAmount().add(monthlyAmount.getMerchantAmount()));
            Long updateAdminStatus = adminService.update(admin);
            merchant.setAmount(merchant.getAmount().subtract(monthlyAmount.getMerchantAmount()));
            Integer updateMerchantStatus = merchantService.updateMerchantAmount(merchant);
            if (updateAdminStatus <= 0 || updateMerchantStatus <= 0) {
                throw new RuntimeException("平台和商家的账单回滚失败");
            }
        }

        // 删除重复
        Integer deleteLong = monthlyAmountMapper.deleteByTimeAndId(id, time);
        System.out.println("删除了" + deleteLong + "行");
        // 月总收入
        BigDecimal amount = new BigDecimal(0);
        // 月admin总收入
        BigDecimal adminAmount = new BigDecimal(0);
        // 月merchant总收入
        BigDecimal merchantAmount = new BigDecimal(0);
        // 完成和取消的订单数量
        Integer finishOrderNumber = 0;
        Integer canceledOrderNumber = 0;
        // 获取当前商家
        Merchant merchant = merchantService.selectById(id);
        // 遍历这个月所有的天
        for (LocalDateTime itemTime = time.withDayOfMonth(1); itemTime.isBefore(time.plusMonths(1).withDayOfMonth(1)); itemTime = itemTime.plusDays(1)) {
            // 刷新底下的每一天
            refreshDay(itemTime, merchant.getId());
        }

        // 获取最靠前的基准管理员
        Admin admin = adminService.listAll().get(0);
        // 获取当月每日的总结
        List<DailyAmount> dailyAmounts = dailyAmountMapper.selectByMonthTime(time, merchant.getId());
        // 遍历这个月每天的记录
        for (DailyAmount dailyAmount : dailyAmounts) {
            amount = amount.add(dailyAmount.getAmount());
            adminAmount = adminAmount.add(dailyAmount.getAdminAmount());
            merchantAmount = merchantAmount.add(dailyAmount.getMerchantAmount());
            finishOrderNumber += dailyAmount.getFinishOrderNumber();
            canceledOrderNumber += dailyAmount.getCanceledOrderNumber();
        }

        MonthlyAmount monthlyAmount = new MonthlyAmount();
        monthlyAmount.setAdminAmount(adminAmount);
        monthlyAmount.setMerchantAmount(merchantAmount);
        monthlyAmount.setTime(time);
        monthlyAmount.setMerchantId(merchant.getId());
        monthlyAmount.setAmount(amount);
        monthlyAmount.setFinishOrderNumber(finishOrderNumber);
        monthlyAmount.setCanceledOrderNumber(canceledOrderNumber);
        monthlyAmountMapper.insertMonthlyAmount(monthlyAmount);
        // 更新merchant数据
        admin.setAmount(admin.getAmount().subtract(merchantAmount));
        merchant.setAmount(merchant.getAmount().add(merchantAmount));
        if (admin.getAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new RuntimeException("数据错误");
        }
        adminService.update(admin);
        merchantService.updateMerchantAmount(merchant); // 更新其余额
    }

    /**
     * 管理端可以手动刷新指定日期的收入情况
     * @param time 传入当前指定的时间
     * @param merchantId 传入指定的商家id
     */
    @Transactional
    @Override
    public void refreshDay(LocalDateTime time, Integer merchantId) {
        Admin admin = adminService.listAll().get(0);
        // 删除重复的元素
        dailyAmountMapper.deleteByTimeAndId(merchantId, time);
        // 获取当前商家
        Merchant merchant = merchantService.selectById(merchantId);
        // 获取今日订单
        List<Order> dailyOrders = getOrderByDayTime(time, merchantId);
        Integer finishOrderNumber = 0;
        Integer canceledOrderNumber = 0;
        BigDecimal amount = new BigDecimal(0);
        for (Order itemOrder : dailyOrders) {
            // 只有已完成：3是待评价订单，4是已经评价的完成的订单
            if (itemOrder.getStatus() == 3 || itemOrder.getStatus() == 4) {
                amount = amount.add(itemOrder.getAmount());
                finishOrderNumber++;
            } else if (itemOrder.getStatus() == -1 || itemOrder.getStatus() == -2) {
                // 取消的订单 -1和-2
                canceledOrderNumber++;
            }
        }
        // 平台抽成
        BigDecimal adminAmount = amount.multiply(merchant.getCommission());
        // 商家收益
        BigDecimal merchantAmount = amount.subtract(adminAmount);
        // 存储抽成
        BigDecimal commission = merchant.getCommission();
        // 调用insert
        DailyAmount dailyAmount = new DailyAmount();
        dailyAmount.setAmount(amount);
        dailyAmount.setAdminAmount(adminAmount);
        dailyAmount.setMerchantAmount(merchantAmount);
        dailyAmount.setCommission(commission);
        dailyAmount.setCanceledOrderNumber(canceledOrderNumber);
        dailyAmount.setFinishOrderNumber(finishOrderNumber);
        dailyAmount.setMerchantId(merchant.getId());
        dailyAmount.setTime(time);
        Integer integer = dailyAmountMapper.insertDailyAmount(dailyAmount);
        if(integer != 1) {
            throw new RuntimeException("订单记录更新失败");
        }
    }

    /**
     * 根据checkOutTime查询Order的列表
     * @param id 商家id
     * @param time 当前需要查询的时间
     * @return 返回列表
     */
    @Override
    public List<Order> searchOrderByCheckoutTime(Integer id, LocalDateTime time) {
        return orderMapper.getOrderByDayTime(time, id);
    }

    /**
     * 改变指定订单的订单状态
     * @param id 订单id
     * @param status 需要修改成的状态
     * @return 返回是否修改成功
     */
    @Override
    public int changeOrderStatus(int id, int status) {
        //更新为已完成需要设置结束时间
        if(status==3){
            Order order = orderMapper.selectByOrderId(id);
            LocalDateTime time= LocalDateTime.now();
            order.setCheckoutTime(time);
            order.setStatus(3);
            orderMapper.update(order);
            return 1;
        }
        return orderMapper.changeOrderStatus(id, status);
    }

    /**
     * 获得amount的信息，主要用于前端显示
     * @param time 当前需要查询的时间
     * @return 返回前端处理数据类型，AdminMoneyInfo为前端显示的model
     */
    @Override
    public JsonResult getMoneyInfo(LocalDateTime time) {
        AdminMoneyInfo adminMoneyInfo = new AdminMoneyInfo();
        adminMoneyInfo.setAdminAmount(adminService.listAll().get(0).getAmount());
        List<DailyAmount> dailyAmounts = dailyAmountMapper.selectByTime(LocalDateTime.now().plusDays(-1));
        BigDecimal money = BigDecimal.ZERO;
        BigDecimal adminMoney = BigDecimal.ZERO;
        for (DailyAmount amount : dailyAmounts) {
            money = money.add(amount.getAmount());
        }
        adminMoneyInfo.setAmountLastDay(money);
        List<DailyAmount> dailyAmounts1 = dailyAmountMapper.selectByTime(LocalDateTime.now().plusDays(-1));
        for(DailyAmount amount : dailyAmounts1) {
            adminMoney = adminMoney.add(amount.getAdminAmount());
        }
        adminMoneyInfo.setAdminAmountLastDay(adminMoney);
        return new JsonResult(0, "", adminMoneyInfo);
    }

    /**
     * 查询当前在minutes分钟内没有支付的订单
     * @param minutes 输入的分钟数
     * @return 返回订单列表
     */
    @Override
    public List<Order> getNoPayOrderByDuration(int minutes) {
        // 计算若干分钟前的时间
        LocalDateTime currentTime = LocalDateTime.now().minusMinutes(minutes);
        // 查询在currentTime时间之前的所有没有支付的订单
        return orderMapper.selectNoPayAndByEndTime(currentTime);
    }
}
